﻿using System;
using System.Drawing;
using System.Windows.Forms;

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;

using BlockEngine.Engine.API;
using BlockEngine.Hosts.Input;

namespace BlockEngine.Network
{
    class Client : GameWindow
    {
        private Engine.Integration.Windows.NotificationIcon NotifyIcon = new Engine.Integration.Windows.NotificationIcon();
        public static bool Paused = false;
        public static bool Wireframe = false;
        public Player Player1 = new Player();
        public MouseInputHost MouseIn = new MouseInputHost();

        public World.Renderer.Cube CubeRenderer = new World.Renderer.Cube();
        public World.Renderer.Chunk ChunkRenderer = new World.Renderer.Chunk();
        public short[, ,] Blocks = new short[32, 32, 32];

        public Client()
            : base(800, 600, GraphicsMode.Default, "BlockEngine")
        {
            VSync = VSyncMode.On;
        }


        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Icon = new Icon(@"Content\\Integration\\Windows\\BlockEngine.ico");
            GL.ClearColor(0.2f, 0.3f, 0.6f, 0.0f);
            MouseIn.WindowCenter = new Point(Bounds.Left + Bounds.Width / 2, Bounds.Top + Bounds.Height / 2);
            Mouse.Move += new EventHandler<MouseMoveEventArgs>(MouseIn.OnMouseMove);
            GL.Enable(EnableCap.DepthTest);
            //GL.Enable(EnableCap.CullFace);
            ChunkRenderer.Render(new Engine.Internal.Point3D(0, 0, 0), Blocks, false);
            NotifyIcon.Message("BlockEngine has started! Enjoy your session! :)");
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);

            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }

        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);

            Cursor.Current = Cursors.Cross;
            if (Keyboard[Key.Escape])
            {
                NotifyIcon.Dispose();
                Environment.Exit(0);
            }
            if (Keyboard[Key.Pause])
                if (Paused)
                {
                    Paused = false;
                }
                else
                {
                    Paused = true;
                }
            if (Keyboard[Key.F8])
                if (!Wireframe)
                    Wireframe = true;
                else
                    Wireframe = false;
            if (Wireframe)
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
            else
                GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
            if (!Paused)
            {
                Title = "BlockEngine";
                if (Keyboard[Key.LControl] && Keyboard[Key.Pause])
                    throw new Exception("You've started debugging! Now debug! Debug like you've never debugged before!!");
                if (Keyboard[Key.W])
                {
                    Player1.Position.X += (float)Math.Cos(Player1.Yaw) * Maths.MoveSpeed * (float)e.Time;
                    //Position.Y += (float)Math.Tan(Pitch) * MoveSpeed * (float)e.Time;
                    Player1.Position.Z += (float)Math.Sin(Player1.Yaw) * Maths.MoveSpeed * (float)e.Time;
                }
                if (Keyboard[Key.S])
                {
                    Player1.Position.X -= (float)Math.Cos(Player1.Yaw) * Maths.MoveSpeed * (float)e.Time;
                    //Position.Y -= (float)Math.Tan(Pitch) * MoveSpeed * (float)e.Time;
                    Player1.Position.Z -= (float)Math.Sin(Player1.Yaw) * Maths.MoveSpeed * (float)e.Time;
                }
                if (Keyboard[Key.A])
                {
                    Player1.Position.X -= (float)Math.Cos(Player1.Yaw + Math.PI / 2) * Maths.MoveSpeed * (float)e.Time;
                    Player1.Position.Z -= (float)Math.Sin(Player1.Yaw + Math.PI / 2) * Maths.MoveSpeed * (float)e.Time;
                }
                if (Keyboard[Key.D])
                {
                    Player1.Position.X += (float)Math.Cos(Player1.Yaw + Math.PI / 2) * Maths.MoveSpeed * (float)e.Time;
                    Player1.Position.Z += (float)Math.Sin(Player1.Yaw + Math.PI / 2) * Maths.MoveSpeed * (float)e.Time;
                }
                if (Keyboard[Key.Space])
                {
                    Player1.Position.Y += Maths.MoveSpeed * (float)e.Time;
                }
                if (Keyboard[Key.LShift] || Keyboard[Key.RShift])
                {
                    Player1.Position.Y -= Maths.MoveSpeed * (float)e.Time;
                }

                MouseIn.MouseDelta = new Vector2(MouseIn.MousePosition.X - PointToClient(MouseIn.WindowCenter).X, MouseIn.MousePosition.Y - PointToClient(MouseIn.WindowCenter).Y);
                Cursor.Position = MouseIn.WindowCenter;

                MouseIn.MouseSpeed.X *= 0.7f;
                MouseIn.MouseSpeed.Y *= 0.7f;
                MouseIn.MouseSpeed.X += MouseIn.MouseDelta.X / 40.0f * (float)e.Time;
                MouseIn.MouseSpeed.Y += MouseIn.MouseDelta.Y / 40.0f * (float)e.Time;

                Player1.Yaw += MouseIn.MouseSpeed.X;
                Player1.Pitch -= MouseIn.MouseSpeed.Y;

                if (Player1.Pitch <= -Maths.HalfPi + 0.01f)
                    Player1.Pitch = -Maths.HalfPi + 0.01f;
                if (Player1.Pitch >= Maths.HalfPi - 0.01f)
                    Player1.Pitch = Maths.HalfPi - 0.01f;
                // Genius

                Vector3 LookAtPoint = new Vector3((float)Math.Cos(Player1.Yaw), (float)Math.Tan(Player1.Pitch), (float)Math.Sin(Player1.Yaw));

                Player1.CameraMatrix = Matrix4.LookAt(Player1.Position, Player1.Position + LookAtPoint, Vector3.UnitY);
            }
            else
                Title = "BlockEngine (PAUSED)";
        }

        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);

            Cursor.Current = Cursors.Cross;
            GL.MatrixMode(MatrixMode.Modelview);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.LoadMatrix(ref Player1.CameraMatrix);

            GL.PushMatrix();

            GL.Translate(1.0f * 2.0f, 0.0f, 1.0f * 2.0f);
            GL.Rotate(90, Vector3.UnitX);

            
            CubeRenderer.Render(new Engine.Internal.Point3D(0, 0, 0), 0, false);
            ChunkRenderer.Render(new Engine.Internal.Point3D(0, 0, 0), Blocks, false);

            GL.PopMatrix();

            SwapBuffers();
        }
    }
}
